#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "brainfk.h"

void* getMem(int index, pool* head) {
    int n = 0;
    pool* tmp = NULL;
    tmp = head;
    for (n = 0; n < index; ++n) {
        if (tmp->next == NULL) {
            tmp->next = (pool*) malloc(sizeof (pool));
            tmp->next->data = (unsigned char*) malloc(BUFF_SIZE * sizeof (unsigned char));
            tmp->next->next = NULL;
        }
        tmp = tmp->next;
    }
    return tmp;
}

int freeMem(pool* head) {
    pool* tmp1;
    tmp1 = head;
    pool* tmp2;
    tmp2 = NULL;
    while (1) {
        tmp2 = tmp1->next;
        free(tmp1->data);
        free(tmp1);
        if (tmp2 == NULL) {
            break;
        }
        tmp1 = tmp2;
    }
    return 0;
}

unsigned char* getCell(int num, pool* head) {
    int m = (int) num / BUFF_SIZE;
    int n = num % BUFF_SIZE;
    pool* tmp = getMem(m, head);
    return (tmp->data + n);
}

int parse(unsigned char* command, int len, pool* head) {
    int i = 0;
    int m;
    int n = i;
    int lsign = 0;
    int rsign = 0;
    int pointer = 0;
    unsigned char* tmp = NULL;
    while (i < len) {
        if (command[i] == '>') {
            pointer++;
        } else if (command[i] == '<') {
            if (pointer == 0) {
                return 1;
            }
            pointer--;
        } else if (command[i] == '+') {
            tmp = getCell(pointer, head);
            *tmp += 1;
            tmp = NULL;
        } else if (command[i] == '-') {
            tmp = getCell(pointer, head);
            *tmp -= 1;
            tmp = NULL;
        } else if (command[i] == '.') {
            tmp = getCell(pointer, head);
            printf("%c", tmp);
            tmp = NULL;
        } else if (command[i] == ',') {
            //scanf("%c",&stack[pointer]);
            tmp = getCell(pointer, head);
            *tmp = getchar();
            tmp = NULL;
        } else if (command[i] == '[') {
            tmp = getCell(pointer, head);
            if (*tmp == 0) {
                int n = i;
                int lsign = 0;
                int rsign = 0;
                while (n < strlen(command)) {
                    if (command[n] == '[') {
                        lsign++;
                    } else if (command[n] == ']') {
                        rsign++;
                    }
                    if (lsign == rsign) {
                        i = n;
                        break;
                    }
                    n++;
                }
            }
            tmp = NULL;
        } else if (command[i] == ']') {
            tmp = getCell(pointer, head);
            if (*tmp != 0) {
                n = i;
                lsign = 0;
                rsign = 0;
                while (n >= 0) {
                    if (command[n] == '[') {
                        lsign++;
                    } else if (command[n] == ']') {
                        rsign++;
                    }
                    if (lsign == rsign) {
                        i = n;
                        break;
                    }
                    n--;
                }
            }
            tmp = NULL;
        } else if (command[i] == 'q' || command[i] == 'Q') {
            return 2;
        }
        i++;
    }
    return 0;
}

int main(int argc,char* argv[]) {
    char myc[300];
    int pointer = 0;
    pool* head = (pool*) malloc(sizeof (pool));
    FILE* fp = NULL;
    int filesize = 0;
    char* file_content = NULL;
    head->data = (unsigned char*) malloc(BUFF_SIZE * sizeof (unsigned char));
    head->next = NULL;

    memset(head->data, 0, BUFF_SIZE);
    if(argc == 2){
        fp = fopen(argv[1],"r");
        fseek(fp,0,SEEK_END);
        filesize = ftell(fp) + 1;
        file_content = (char*)malloc(filesize * sizeof(char));
        memset(file_content, 0, filesize * sizeof(char));
        fread(file_content,sizeof(char),filesize,fp);
        return parse(file_content, filesize, head);
    }else{
        while (1) {
            printf("$ ");
            scanf("%s", myc);
            if (parse(myc, strlen(myc), head) == 2) {
                return 0;
            }
            memset(myc, 0, 300);
        }
    }
}
